使用 Kanzi Engine API 创建动画和时间线

Kanzi 动画系统由动画和时间线组成。动画定义了特定类型的值如何随着时间的推移而变化,时间线会将动画映射到您要动画化的对象的属性。

您可以使用 Kanzi Engine API 来创建动画和时间线:

使用 Kanzi Engine API 创建从-至动画

从-至动画定义了将某个属性从哪个值更改为哪个值。您可以忽略这两个值中的任何一个,以便从当前值动画化或者动画化至属性的当前值。从-至动画使用一条缓动曲线来定义动画的变化速度。您可以使用 Kanzi 附带其中一种缓动曲线,也可以定义自己的缓动曲线。

要创建从-至动画:

//创建一个使用线性缓动函数且时长为 2 秒钟的从-至动画。
//作为一个初始值,动画使用要动画化的节点中的属性的当前值。
//动画会将要动画化的节点中的属性的终值设置为 200。
//您可以设置动画要动画化时间线中的哪个节点。
FloatLinearFromToAnimationSharedPtr linearAnimation = FloatLinearFromToAnimation::create(domain, chrono::seconds(2), nullopt, 200.0f);

要使用从-至动画动画化节点中的某个属性值:

//创建一个属性时间线并将 linearAnimation 从-至动画应用于布局宽度 (Layout Width) 属性,
//以动画化当前节点的宽度。
PropertyAnimationTimelineSharedPtr propertyTimeline = PropertyAnimationTimeline::create(domain, ".", Node::WidthProperty, linearAnimation);

要使用从-至动画动画化节点中的某个属性字段值:

//创建一个属性字段动画时间线并将其应用于当前节点的渲染变换 (Render Transformation) 属性。
PropertyFieldAnimationTimelineSharedPtr propertyFieldTimeline = PropertyFieldAnimationTimeline::create(domain, ".", Node2D::RenderTransformationProperty);
//使用 linearAnimation 从-至动画对渲染变换 (Render Transformation) 属性的缩放 X (Scale X) 属性字段进行动画化,
//以缩放 x 轴上的当前节点。
propertyFieldTimeline->addEntry(PropertyFieldScaleX, linearAnimation);

要创建使用向后缓动曲线和缓出模式的浮点从-至动画:

//定义 FloatBackFromToAnimation,以使用浮点值和向后缓动函数。
typedef FromToAnimation<float, BackEasingFunction> FloatBackFromToAnimation;
typedef shared_ptr<FloatBackFromToAnimation> FloatBackFromToAnimationSharedPtr;
//创建一个使用向后缓动函数且时长为 5000 毫秒的从-至动画。
//动画将要动画化的节点中的属性的初值设置为 100,
//并将属性的终值设置为 300。
FloatBackFromToAnimationSharedPtr backAnimation = FloatBackFromToAnimation::create(domain, chrono::milliseconds(5000), nullopt, 300.0f);
//将 backAnimation 从-至动画的缓动模式设置为缓出 (Ease out)。
backAnimation->setEasingMode(AnimationEaseOut);

要播放动画而不管时间线类型如何:

//为 item2d 中定义的节点创建回放上下文和时间线回放。
SceneGraphTimelinePlaybackContext context(*item2d);
//为 propertyFieldTimeline 中定义的时间线创建回放。
TimelinePlaybackSharedPtr playback = propertyFieldTimeline->createPlayback(context);
//开始执行动画化。
domain->getRootTimelineClock()->addTimelinePlayback(playback);

有关详细信息,请参阅 API reference 中的 FromToAnimation 类。

使用 Kanzi Engine API 创建关键帧动画

关键帧动画使用的关键帧定义了属性值以及动画要在何时达到值。在Kanzi 中,您可以创建线性、步进以及贝塞尔样条关键帧。

要创建关键帧动画:

//创建一个浮点关键帧动画。
FloatKeyframeAnimationSharedPtr keyframeAnimation = FloatKeyframeAnimation::create(domain);
//创建关键帧并将它们添加到关键帧动画中。关键帧动画包含 2 个线性关键帧。
//在 0 秒处创建一个值为 0 的线性关键帧。
keyframeAnimation->addLinearKeyframe(chrono::seconds::zero(), 0.0f);
//在 1 秒处创建一个值为 100 的线性关键帧。
keyframeAnimation->addLinearKeyframe(chrono::seconds(1), 100.0f);

要使用关键帧动画动画化节点中的某个属性值:

//创建一个属性时间线并将 keyframeAnimation 关键帧动画应用于布局宽度 (Layout Width) 属性,
//以动画化当前节点的宽度。
PropertyAnimationTimelineSharedPtr propertyTimeline = PropertyAnimationTimeline::create(domain, ".", Node2D::WidthProperty, keyframeAnimation);

要使用关键帧动画动画化节点中的某个属性字段值:

//创建一个属性字段动画时间线并将其应用于当前节点的渲染变换 (Render Transformation) 属性。
PropertyFieldAnimationTimelineSharedPtr propertyFieldTimeline = PropertyFieldAnimationTimeline::create(domain, ".", Node2D::RenderTransformationProperty);
//使用 keyframeAnimation 关键帧动画对渲染变换 (Render Transformation) 属性的旋转 Z (Rotation Z) 属性字段进行动画化,
//以旋转当前节点。
propertyFieldTimeline->addEntry(PropertyFieldRotationZ, keyframeAnimation);

要创建一个使用贝塞尔曲线关键帧在 8 字形路径上移动对象的关键帧动画:

//创建两个浮点关键帧动画:一个用于动画化 x 轴上的对象,
//另一个用于动画化 y 轴上的对象。
//创建使用线性关键帧的浮点关键帧动画 keyframeAnimationX,
//以动画化 x 轴上对象的移动。
FloatKeyframeAnimationSharedPtr keyframeAnimationX = FloatKeyframeAnimation::create(domain);
//在 0 秒处创建一个值为 0 的线性关键帧。
keyframeAnimationX->addLinearKeyframe(chrono::seconds::zero(), 0.0f);
//在 4 秒处创建一个值为 4 的线性关键帧。
//在关键帧处,对象在 x 轴上达到最远的点。
keyframeAnimationX->addLinearKeyframe(chrono::seconds(4), 4.0f);
//在 8 秒处创建一个值为 0 的线性关键帧。
//在关键帧处,对象将回到它在第一个关键帧处所处的那个位置。
keyframeAnimationX->addLinearKeyframe(chrono::seconds(8), 0.0f);

//创建使用贝塞尔曲线关键帧的浮点关键帧 keyframeAnimationY,
//以在动画化 y 轴上对象的移动。
FloatKeyframeAnimationSharedPtr keyframeAnimationY = FloatKeyframeAnimation::create(domain);
//在 0 秒处创建一个值为 0 的线性关键帧。当使用贝塞尔曲线关键帧时,
//您可以对第一个关键帧使用任何类型的关键帧,原因在于您只需要
//让关键帧提供有关开始位置的信息。
keyframeAnimationY->addLinearKeyframe(chrono::seconds::zero(), 0.0f);
//在 4 秒处创建一个值为 0 并具有两个控制点的贝塞尔曲线关键帧。
//您可以使用控制点设置关键帧的位置。
keyframeAnimationY->addBezierKeyframe(chrono::seconds(4), 0.0f, Vector2(0.5f, 4.0f), Vector2(0.5f, -4.0f));
//在 8 秒处创建一个值为 0 并具有两个控制点的贝塞尔曲线关键帧。
//关键帧使用相同的控制点,但由于 keyframeAnimationX
//动画将 x 轴上的对象移回到其开始位置,因此关键帧
//是上一个关键帧的镜像图像。
keyframeAnimationY->addBezierKeyframe(chrono::seconds(8), 0.0f, Vector2(0.5f, 4.0f), Vector2(0.5f, -4.0f));

//创建一个属性字段动画时间线并将其应用于当前节点的渲染变换 (Render Transformation) 属性。
PropertyFieldAnimationTimelineSharedPtr timeline = PropertyFieldAnimationTimeline::create(domain, ".", Node3D::RenderTransformationProperty);
//使用 keyframeAnimationX 关键帧动画对渲染变换 (Render Transformation) 属性的平移 X (Translation X) 属性字段进行动画化,
//以移动 x 轴上的当前节点。
timeline->addEntry(PropertyFieldTranslationX, keyframeAnimationX);
//使用 keyframeAnimationY 关键帧动画对渲染变换 (Render Transformation) 属性的平移 Y (Translation Y) 属性字段进行动画化,
//以移动 y 轴上的当前节点。
timeline->addEntry(PropertyFieldTranslationY, keyframeAnimationY);

要播放动画而不管时间线类型如何:

//为 item2d 中定义的节点创建回放上下文和时间线回放。
SceneGraphTimelinePlaybackContext context(*item2d);
//为 propertyFieldTimeline 中定义的时间线创建回放。
TimelinePlaybackSharedPtr playback = propertyFieldTimeline->createPlayback(context);
//开始执行动画化。
domain->getRootTimelineClock()->addTimelinePlayback(playback);

有关详细信息,请参阅 API reference 中的 KeyframeAnimation 类。

使用 Kanzi Engine API 创建属性时间线

属性时间线会将动画应用于对象的属性。例如,要更改图像 (Image) 节点的布局尺寸,请使用属性时间线对节点的布局宽度 (Layout Width)布局高度 (Layout Height) 属性进行动画化。

要创建属性时间线:

//创建一个属性时间线并将 linearAnimation 动画应用于布局宽度 (Layout Width) 属性
//以动画化当前节点的宽度。
PropertyAnimationTimelineSharedPtr propertyTimeline = PropertyAnimationTimeline::create(domain, ".", Node::WidthProperty, linearAnimation);

要播放动画而不管时间线类型如何:

//为 item2d 中定义的节点创建回放上下文和时间线回放。
SceneGraphTimelinePlaybackContext context(*item2d);
//为 propertyFieldTimeline 中定义的时间线创建回放。
TimelinePlaybackSharedPtr playback = propertyFieldTimeline->createPlayback(context);
//开始执行动画化。
domain->getRootTimelineClock()->addTimelinePlayback(playback);

有关详细信息,请参阅 API reference 中的 PropertyAnimationTimeline 类。

使用 Kanzi Engine API 创建属性字段时间线

属性字段时间线会将动画应用于对象属性的一个或多个域。例如,您可以为每个颜色通道使用单独的动画,以更改文本块 (Text Block) 节点中的文本的颜色。

要创建属性字段时间线:

//创建一个属性字段时间线并将其应用于当前节点的渲染变换 (Render Transformation) 属性。
PropertyFieldAnimationTimelineSharedPtr propertyFieldTimeline = PropertyFieldAnimationTimeline::create(domain, ".", Node2D::RenderTransformationProperty);
//使用 linearAnimation 动画对渲染变换 (Render Transformation) 属性的缩放 X (Scale X) 属性字段进行动画化,
//以缩放 x 轴上的当前节点。
propertyFieldTimeline->addEntry(PropertyFieldScaleX, linearAnimation);

要播放动画而不管时间线类型如何:

//为 item2d 中定义的节点创建回放上下文和时间线回放。
SceneGraphTimelinePlaybackContext context(*item2d);
//为 propertyFieldTimeline 中定义的时间线创建回放。
TimelinePlaybackSharedPtr playback = propertyFieldTimeline->createPlayback(context);
//开始执行动画化。
domain->getRootTimelineClock()->addTimelinePlayback(playback);

有关详细信息,请参阅 API reference 中的 PropertyFieldAnimationTimeline 类。

使用 Kanzi Engine API 创建并行时间线

并行时间线允许您将 Kanzi 同时播放的那些时间线分组。当最后一个子时间线结束时,并行时间线即告结束。使用时间线可以组织时间线集合和创建时间线合成。

将子时间线添加到并行时间线时,子时间线的集合体将构成并行时间线的内容。这意味着并行时间线的所有回放属性都将应用于其子时间线。

要创建并行时间线:

//创建一个并行时间线。
ParallelTimelineSharedPtr parallelTimeline = ParallelTimeline::create(domain);
//将 propertyTimeline 和 propertyFieldTimeline 时间线添加到并行时间线中。并行时间线会同时
//播放这两个时间线。
parallelTimeline->addChild(propertyTimeline);
parallelTimeline->addChild(propertyFieldTimeline);

要播放动画而不管时间线类型如何:

//为 item2d 中定义的节点创建回放上下文和时间线回放。
SceneGraphTimelinePlaybackContext context(*item2d);
//为 propertyFieldTimeline 中定义的时间线创建回放。
TimelinePlaybackSharedPtr playback = propertyFieldTimeline->createPlayback(context);
//开始执行动画化。
domain->getRootTimelineClock()->addTimelinePlayback(playback);

有关详细信息,请参阅 API reference 中的 ParallelTimeline 类。

使用 Kanzi Engine API 配置时间线

时间线由一组连续播放的迭代组成,并在指定的开始时间开始播放。每个迭代都是时间线内容的一个连续部分,Kanzi 将按指定的方式对其进行播放。时间线内容可以包含一个或多个动画或子时间线。

使用时间线回放属性,您可以定义 Kanzi 如何播放时间线内容。例如,您可以设置动画的速度、重复次数以及回放方向。 Kanzi 按如下顺序应用时间线属性:

  1. 剪辑属性用于设置要在迭代中播放的时间线内容的部分:
  2. 持续时间标度用于设置(构成剪辑的)时间线内容的播放时长。
    例如,如果将持续时间标度设置为 2,时间线内容会花费比时间线内容中定义的时长多一倍的时间进行播放。
    构成剪辑并设置了持续时间标度的时间线内容会显示迭代的内容。
  3. 方向行为用于设置迭代内容在哪个方向进行播放。将方向行为设置为:
  4. 重复计数用于设置迭代内容的重复次数。将重复计数设置为 0 将使迭代无限重复或直到停止为止。
  5. 开始时间用于设置何时开始播放时间线的第一个迭代。将开始时间设置为:

只有在时间线的全局时间超过开始时间属性之后,时间线才会应用自己的内容。在 Kanzi 播放时间线直到结束之后,时间线会从末尾无数次应用自己的内容,直到被移除为止。如果您将某个并行时间线的重复计数设置为多次重复,并为其添加了一个具有非零正开始时间的时间线,则子时间线只会在其全局时间超过其开始时间之后才会在并行时间线的每个迭代的开头开始播放。

请注意,并非所有的时间线回放属性组合都有效。例如,如果将时间线的重复计数设置为无限并将时间线作为一个子时间线添加到并行时间线中,则并行时间线的内容持续时间将变得无限长。在这种情况下,会禁止将并行时间线的方向行为设置为反向,原因在于反转无限内容没有任何意义。如果将方向行为设置为反向,Kanzi Engine 会在内部将其反转为正常方向,并在日志中打印一条警告消息。

要设置时间线剪辑:

//将剪辑开始时间设置为 500 毫秒。当动画开始播放时,会跳过前 500 毫秒。
timeline->setClipStartTime(chrono::milliseconds(500));
//将剪辑的持续时间设置为 1000 毫秒。动画将在回放 1000 毫秒之后(即 1500 毫秒处)结束。
timeline->setClipDuration(chrono::milliseconds(1000));

要设置时间线的持续时间、方向行为和重复计数:

//将动画的持续时间标度设置为 2。只要按照动画中定义的方式播放,动画就会播放两次。
timeline->setDurationScale(2.0f);
//将动画的方向行为设置为往复 (pingpong)。当动画到达末尾时,它将回弹并继续沿相反方向朝着开头方向播放。
timeline->setDirectionBehavior(Timeline::DirectionBehaviorPingPong);
//将重复计数设置为 2。当动画完成往复回放之后再次到达开头时,将动再次重复播放动画。
timeline->setRepeatCount(2);
//将重复计数设置为无限。动画会无休无止地播放,或者播放到被明确停止为止。
timeline->setRepeatCount(0);

要设置时间线的开始时间:

//将时间线开始时间设置为 100 毫秒。当时间线的全局时间达到 100 毫秒时,时间线会开始播放自己的第一个迭代。
timeline->setStartTime(chrono::milliseconds(100));

有关详细信息,请参阅 API reference 中的 Timeline 类。

另请参阅

动画系统

教程:创建关键帧动画

创建关键帧动画

更改关键帧之间的插值模式

编辑时间线序列

编辑动画剪辑

动画最佳实践